﻿using System.Diagnostics;
using System.Linq;
using MathParser.DataModel;

namespace MathParser {
    public partial class Parser {
        readonly OperationMapper mapper = new OperationMapper();

        private Operation ScanTerm(out int posInsideTerm) {
            Entferne_klammernpaar_für_binär_op();
            ExpandUnaryMinus();
            return GetTyp(out posInsideTerm);
        }

        private Operation GetTyp(out int posInsideTerm) {
            var typ = Operation.No;
            var index = -1;

            foreach (var map in this.mapper.ConstMap.Where(map => map.Key == this.Expression)) {
                typ = map.Value;
                break;
            }

            foreach (var map in this.mapper.UnärMap.Where(map => Expression.StartsWith(map.Key + "("))) {
                typ = map.Value;
                break;
            }

            // Fakultät
            if (Ist_binär_op_ausserhalb_klammern("!")) {
                index = Idx_binär_op_ausserhalb_klammern("!");
                typ = Operation.Fakultät;
            }

            foreach (var map in this.mapper.BinärMap.Where(map => Ist_binär_op_ausserhalb_klammern(map.Key))) {
                index = Idx_binär_op_ausserhalb_klammern(map.Key);
                typ = map.Value;
                break;
            }

            if (typ == Operation.No && Ist_zahl()) {
                typ = Operation.Zahl;
            }

            posInsideTerm = index;
            return typ;
        }

        private bool Ist_zahl() {
            var istZahl = true;
            try {
                double.Parse(this.Expression);
            }
            catch {
                Error = ErrorType.TermAufloesung;
                istZahl = false;
            }
            return istZahl;
        }

        private void ExpandUnaryMinus() {
            if (this.mapper.UnärMap.Any(map => Expression.StartsWith("-" + map.Key + "("))) {
                Expression = "-1*" + Expression.Substring(1);
                return;
            }

            if ((Expression.StartsWith("-x")) || (Expression.StartsWith("-("))) {
                Expression = "-1*" + Expression.Substring(1);
            }
        }

        private void Entferne_klammernpaar_für_binär_op() {
            bool isOpFound;
            do {
                if ((!Ist_binär_op_ausserhalb_klammern("-")) && (!Ist_binär_op_ausserhalb_klammern("+")) && (!Ist_binär_op_ausserhalb_klammern("*"))
                    && (!Ist_binär_op_ausserhalb_klammern("/")) && (!Ist_binär_op_ausserhalb_klammern("^"))) {
                    isOpFound = Ist_klammerpaar_entfernt();
                }
                else {
                    isOpFound = false;
                }
            }
            while (isOpFound);
        }

        private bool Ist_binär_op_ausserhalb_klammern(string binärCharToFind) {
            return Idx_binär_op_ausserhalb_klammern(binärCharToFind) > (binärCharToFind == "-" ? 0 : -1);
        }

        private int Idx_binär_op_ausserhalb_klammern(string binCharToFind) {
            var index = -1;
            var klammerEbene = 0;
            for (var i = 0; i < Expression.Length; i++) {
                switch (Expression[i].ToString()) {
                case "(":
                    klammerEbene++;
                    break;
                case ")":
                    klammerEbene--;
                    break;
                }
                if ((Expression[i].ToString() == binCharToFind) && (klammerEbene == 0)) {
                    index = i;
                }
            }
            return index;
        }
        
        private bool Ist_klammerpaar_entfernt() {
            if ((Expression.StartsWith("(")) && (Expression.EndsWith(")"))) {
                Expression = Expression.Substring(1, Expression.Length - 2);
                return true;
            }
            return false;
        }

    }
}